package com.tsd.core.utils;


import com.tsd.core.vo.HlpException;
import com.tsd.core.vo.WeekInfo;

import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

/**
 * 日期工具栏
 * SimpleDateFormat不是线程安全，所有每次使用都需要new一个对象
 *
 * @Author Hillpool
 * @Date 2022-08-28  16:08
 */
public class DateUtil {
    /**
     * 一天的毫秒数
     */
    static long oneDay = 24 * 3600 * 1000;
    /**
     * 一小时毫秒数
     */
    private static final double ONE_HOUR = 60 * 60 * 1000;
    /**
     * 一分钟毫秒数
     */
    private static final double ONE_MINUTE = 60 * 1000;

    /**
     * 返回某天所在的周次、月份和年份。
     * 每周的开始时间必须是周日，无法改变
     * 如果刚好是跨年的周次，则将该周归到第二年
     *
     * @param d 日期
     * @return
     */
    public static WeekInfo getWeekInfo(Date d) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(d);
        int week1 = calendar.get(Calendar.WEEK_OF_YEAR);
        int year = calendar.get(Calendar.YEAR);
        int month1 = calendar.get(Calendar.MONTH) + 1;
        int month = getMonth(year, week1);
        if (month1 == 12 && month == 1) {
            //刚好跨年
            year++;
            week1 = 1;
        }
        WeekInfo wi = new WeekInfo();
        wi.setYear(year);
        wi.setMonth(month);
        wi.setWeek(week1);
        return wi;
    }

    /**
     * 根据年份、周次获取所在的月份
     *
     * @param year
     * @param week
     * @return
     */
    public static Integer getMonth(Integer year, Integer week) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.WEEK_OF_YEAR, week);
        calendar.add(Calendar.DAY_OF_WEEK, 3);
        return calendar.get(Calendar.MONTH) + 1;
    }

    /**
     * 根据年份、月份获取该月份的第一个全年周次
     *
     * @param year
     * @param month
     * @return
     * @throws ParseException
     */
    public static Integer getMonthFirstWeek(int year, int month) throws ParseException {
        Date d = HlpUtils.string2Date("" + (year * 10000 + month * 100 + 1), HlpUtils.Format_YyyyMMdd);
        WeekInfo w = getWeekInfo(d);
        if (w.getMonth() == month) {
            return w.getWeek();
        } else {
            return w.getWeek() + 1;
        }
    }

    /**
     * 获取一个月的周数量
     *
     * @param year
     * @param month
     * @return
     * @throws ParseException
     */
    public static Integer getMonthWeekCount(int year, int month) throws HlpException {
        try {
            int first = getMonthFirstWeek(year, month);
            int last = getMonthLastWeek(year, month);
            return last - first + 1;
        } catch (ParseException e) {
            throw new HlpException("产生日期日期解释错误");
        }
    }

    /**
     * 根据年份、月份获取该月份的最后一个全年周次
     *
     * @param year
     * @param month
     * @return
     * @throws ParseException
     */
    public static Integer getMonthLastWeek(int year, int month) throws ParseException {
        Date d = HlpUtils.string2Date("" + (year * 10000 + month * 100 + 1), HlpUtils.Format_YyyyMMdd);
        d = HlpUtils.getNextDateByMonth(d, 1);
        WeekInfo w = getWeekInfo(d);
        if (w.getMonth() == month) {
            return w.getWeek();
        } else {
            if (w.getYear() == year) {
                return w.getWeek() - 1;
            } else {
                return 52;//跨年则返回最后一周
            }
        }
    }

    /**
     * 根据月份获取上一月份
     *
     * @param yyyyMM
     * @return
     */
    public static Integer getLastMonth(Integer yyyyMM) {
        Integer year = yyyyMM / 100;
        Integer month = yyyyMM - year * 100;
        if (month == 1) {
            month = 12;
            year = year - 1;
        } else {
            month = month - 1;
        }
        return year * 100 + month;
    }

    /**
     * 根据年份和周次获取第一天或最后一天
     *
     * @param year 年份
     * @param week 周次
     * @param flag 是否最后一天，false-第一天，true-最后一天
     * @return
     */
    public static String getWeekFirstOrLastDate(Integer year, Integer week, boolean flag) {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY);
        cal.set(Calendar.YEAR, year);
        cal.set(Calendar.WEEK_OF_YEAR, week);
        if (flag) {
            cal.set(Calendar.DAY_OF_WEEK, Calendar.FRIDAY);
        } else {
            cal.set(Calendar.WEEK_OF_YEAR, week - 1);
        }
        return HlpUtils.date2String(cal.getTime(), HlpUtils.Format_Yyyy_MM_dd);
    }

    /**
     * 根据年份和月份获取第一天或最后一天
     *
     * @param year  年份
     * @param month 月份
     * @param flag  是否最后一天，false-第一天，true-最后一天
     * @return
     */
    public static String getMonthFirstOrLastDate(Integer year, Integer month, boolean flag) {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, year);
        if (flag) {
            cal.set(Calendar.MONTH, month);
            cal.set(Calendar.DAY_OF_MONTH, 0);
        } else {
            cal.set(Calendar.MONTH, month - 1);
            cal.set(Calendar.DAY_OF_MONTH, 1);
        }
        return HlpUtils.date2String(cal.getTime(), HlpUtils.Format_Yyyy_MM_dd);
    }

    public static void main(String[] args) {
        try {
            Date d = HlpUtils.string2Date("2017-08-02", HlpUtils.Format_YyyyMMdd);
            WeekInfo wi = getWeekInfo(d);
//			System.out.println(wi.getYear());
//			System.out.println(wi.getMonth());
            System.out.println(wi.getWeek());
//			Date d2 = HlpUtils.dateFormatterYyyy_MM_dd.parse("2017-09-01");
//			WeekInfo wi2 = getWeekInfo(d2);
//			System.out.println(wi2.getMonth());
//			System.out.println(wi2.getWeek());
            int t = getMonthFirstWeek(2017, 11);
            int t2 = getMonthLastWeek(2017, 11);
            System.out.println(t);
            System.out.println(t2);
            System.out.println(getMonthFirstOrLastDate(2017, 12, false));
            System.out.println(getMonthFirstOrLastDate(2017, 12, true));
            System.out.println(getMonth(2017, 46));
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public static void main2(String[] args) {
        int t = getMonth(2017, 35);
        System.out.println(t);
    }

    /**
     * 计算2个日期之间的相差天数
     * 如果日期不同，则各取0点进行比较
     * 所以存在2020-02-04 00:02 - 2020-02-03 23:59=1的情况
     *
     * @param date1
     * @param date2
     * @return
     * @throws ParseException
     */
    public static int dateSub(Date date1, Date date2) throws ParseException {
        int day1 = getYyyyMMdd(date1);
        int day2 = getYyyyMMdd(date2);
        if (day1 == day2) {
            return 0;
        } else {
            Date d1 = HlpUtils.string2Date("" + day1, "yyyyMMdd");
            Date d2 = HlpUtils.string2Date("" + day2, "yyyyMMdd");
            return (int) ((d1.getTime() - d2.getTime()) / oneDay);
        }
    }

    /**
     * 获取月旬 三旬: 上旬1-10日 中旬11-20日 下旬21-31日
     *
     * @param date
     * @return
     */
    public static int getTenDay(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int i = calendar.get(Calendar.DAY_OF_MONTH);
        if (i < 11) {
            return 1;
        } else if (i < 21) {
            return 2;
        } else {
            return 3;
        }
    }

    /**
     * 获取时间标记，0-凌晨（0～6点前）、1-上午（6点～12点前）、2-下午（12点～18点前）、3-夜间（18点～0点前）
     *
     * @param date
     * @return
     */
    public static int getTimeTag(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int i = calendar.get(Calendar.HOUR_OF_DAY);
        if (i < 6) {
            return 0;
        } else if (i < 12) {
            return 1;
        } else if (i < 18) {
            return 2;
        } else {
            return 3;
        }
    }

    /**
     * 获取yyyy
     *
     * @param date
     * @return
     */
    public static int getYyyy(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(Calendar.YEAR);
    }

    /**
     * 获取mm
     *
     * @param date
     * @return
     */
    public static int getMm(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(Calendar.MONTH) + 1;
    }

    /**
     * 获取dd
     *
     * @param date
     * @return
     */
    public static int getDd(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(Calendar.DATE);
    }

    public static int getYyyyMM(Date date) {
        return Integer.parseInt(HlpUtils.date2String(date, "yyyyMM"));
    }

    public static int getYyyyMMdd(Date date) {
        return Integer.parseInt(HlpUtils.date2String(date, "yyyyMMdd"));
    }

    /**
     * excel文件读取的日期数字转为日期
     * Java读取excel中日期结果是计算1900-0-1之后到当前日期，一共有多少天，需要转换
     *
     * @param days
     * @return
     */
    public static Date excelDateInt2Date(int days) {
        Calendar calendar1 = new GregorianCalendar(1900, 0, -1);
        Date date = calendar1.getTime();
        date = HlpUtils.getNextDate(date, days);
        return date;
    }

    /**
     * yyyy,mm,dd转为日期对象
     *
     * @param yyyy 年
     * @param mm   月
     * @param dd   日
     * @return
     */
    public static Date getDate(int yyyy, int mm, int dd) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, yyyy);
        calendar.set(Calendar.MONTH, mm - 1);
        calendar.set(Calendar.DATE, dd);
        return calendar.getTime();
    }

    /**
     * 计算2个日期之间的相差小时数
     *
     * @param date1
     * @param date2
     * @return
     * @throws ParseException
     */
    public static double hourSub(Date date1, Date date2) {
        double duration = date1.getTime() - date2.getTime();
        double hour = DoubleUtil.div(duration, ONE_HOUR);
        return Math.abs(hour);
    }

    /**
     * 计算2个日期之间的相差分钟数
     *
     * @param date1
     * @param date2
     * @return
     * @throws ParseException
     */
    public static double minuteSub(Date date1, Date date2) {
        double duration = date1.getTime() - date2.getTime();
        double minute = DoubleUtil.div(duration, ONE_MINUTE);
        return Math.abs(minute);
    }
}
